package pl.edu.agh.se.carsexpertsystem.engine;

import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.SequenceInputStream;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.drools.RuleBase;
import org.drools.RuleBaseFactory;
import org.drools.StatefulSession;
import org.drools.compiler.DroolsParserException;
import org.drools.compiler.PackageBuilder;
import org.drools.compiler.PackageBuilderErrors;
import pl.edu.agh.se.carsexpertsystem.Main;
import pl.edu.agh.se.carsexpertsystem.fact.Fact;
import pl.edu.agh.se.carsexpertsystem.model.CarModel;
import pl.edu.agh.se.carsexpertsystem.model.CarsHolder;

/**
 * Odpala reguly na zadanych faktach i mozliwych rozwiazan.
 * @author piotrek
 */
public class DroolsRunner {
    
    private static final String DRL_FILE = "/rules.drl";
    private static final String DRL_CARS_FILE = "/cars.drl";
    
    private List<CarModel> cache = null;
    private static RuleBase rbase = RuleBaseFactory.newRuleBase();
    private static PackageBuilder pbuilder = new PackageBuilder();
    private static StatefulSession sessionObject;
    private Map<String, CarModel> allCars;
    
    public DroolsRunner(Map<String, CarModel> conclusions, List<Fact> facts){
        allCars = conclusions;
        
        initializeDrools();
        initializeFacts( facts );
    }
    
    public List<CarModel> getResults(){
        if(cache == null)
            runRules();
        
        return cache;
    }

    private void runRules() {
        CarsHolder carsHolder = new CarsHolder();
        sessionObject.insert(carsHolder);
        
        sessionObject.fireAllRules();
        
        cache = new LinkedList<>();
        for(String carName : carsHolder.getCars()){
            CarModel car = allCars.get(carName);
            if(car == null)
                throw new RuntimeException("Nie ma takiego samochodu \"" + car.getName() + "\"");
            
            cache.add(car);
        }
    }

    private void initializeDrools() {
        try {
            Reader reader = new InputStreamReader( new SequenceInputStream( Main.class.getResourceAsStream(DRL_FILE), Main.class.getResourceAsStream(DRL_CARS_FILE)) );
            pbuilder.addPackageFromDrl(reader);
        } catch (DroolsParserException | IOException ex) {
            Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
        }

        PackageBuilderErrors errors = pbuilder.getErrors();

        if (errors.getErrors().length > 0) {
            System.out.println("Some errors exists in packageBuilder");
            for (int i = 0; i < errors.getErrors().length; i++) {
                System.out.println(errors.getErrors()[i]);
            }
            throw new IllegalArgumentException("Could not parse knowledge.");
        }
        
        try {
            rbase.addPackage(pbuilder.getPackage());
        } catch (Exception e) {
            System.out.println("Error: " + e);
        }
        
        sessionObject = rbase.newStatefulSession();
    }
    
    private void initializeFacts(List<Fact> facts){
        for(Fact fact : facts){
            sessionObject.insert(fact);
        }
    }
}
